	//Global variables:
	var _map;
  
	var blip;
	var _blipBounds;
	var _followCar = true;

	var _location = new google.maps.LatLng(0, 0);
	var _velocity = 0;  
	var _bearing = 0;

	var _pointsArray = [];
   		
   	//Functions:
    //Callback from android app:
  	function onUpdate()
  	{
		_location = new google.maps.LatLng(window.android.getLatitude(), window.android.getLongitude());
		_velocity = window.android.getSpeed();
		_bearing = window.android.getBearing();
		
		changeLocation();
  	}
  	
   	function updatePosViaGeoloc(position)
   	{
		_location = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
	   	_velocity = position.coords.speed;
	   	_bearing = position.coords.heading;
	   	
       	changeLocation();	
   	}
  
  	function changeLocation()
  	{
		blip.setPosition(_location);
		checkBlipBounds();
		
		//Send new location to backend:
		transmitPoint();
  	}
  	
  	function checkBlipBounds()
  	{
  		if (_followCar == true)
  		{
			if (_blipBounds.contains(_location) == false)
			{
				_map.panTo(_location);
	
				//update bounds
				var NE = new google.maps.LatLng(_location.lat() + 0.001, _location.lng() + 0.001, true); //111m above right
				var SW = new google.maps.LatLng(_location.lat() - 0.001, _location.lng() - 0.001, true); //111m below left
  			
				_blipBounds = new google.maps.LatLngBounds(SW, NE);
  			
				clearPoints();
				sendRequestForPoints();
			}
  		}
  	}
  	
  	function transmitPoint()
  	{
  		var xmlhttp;
  		
  		if (window.XMLHttpRequest) //new browsers (IE7+, firefox, etc)
		{
			xmlhttp = new XMLHttpRequest();
		}
		else //IE 5 6
		{
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		
		var querystring = "http://jam-dodge.enox.co.za/LogPoint.php?lat=" + _location.lat() + "&lng=" + _location.lng() + "&s=" + _velocity + "&b=" + _bearing;
		
  		xmlhttp.open("GET", querystring, true); //true is for asynchronous request
  		//xmlhttp.onreadystatechange = function () { }
  		xmlhttp.send();
  	}
  	
  	function sendRequestForPoints()
  	{
  		//console.log("Getting points");
  		//note JS interpreter is really slow, caching is fast.
  		var bounds = _map.getBounds();
  		var NE = bounds.getNorthEast();
  		var SW = bounds.getSouthWest();
  		var top = NE.lng();
  		var right = NE.lat();
  		var bottom = SW.lng();
  		var left = SW.lat();
  		
  		var xmlhttp;
  		
  		if (window.XMLHttpRequest)
		{
			xmlhttp = new XMLHttpRequest();
		}
		else
		{
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		
		var querystring = "http://jam-dodge.enox.co.za/GetPointsString.php?t=" + top + "&b=" + bottom + "&l=" + left + "&r=" + right;
		
  		xmlhttp.open("GET", querystring, true); //true is for asynchronous request
  		xmlhttp.onreadystatechange = function () {
  				if (xmlhttp.readyState == 4)
  				{
  					//if (req.status == 200) //perhaps not neccisary, running on same server
  					//{
  						parseFromPointsRequest(xmlhttp.responseText);
  					//}
  				}
  			}
  		xmlhttp.send();
  	}
  	
  	function parseFromPointsRequest(pointString)
  	{
  		var lines = pointString.split(";");
  		
  		var len = lines.length - 1;
  		for (var i = len; i--; ) //faster than normal for loop (less comparisons)
  		{
  			var parts = lines[i].split(" ");
  			parts[3] = "#" + parts[3]; //colour comes without the # for bandwidth efficiency
  			
  			addPoint(parts[0],parts[1],parts[2],parts[3],parts[4]);
  		}
  	}
  	
  	function addPoint(latitude, longitude, bearing, colour, speed)
  	{
  		/*if (speed == 0)
  			speed = 1; //show points even if stationary
  		
  		var len = speed * 0.00009; //m/s to deg/s
  		var nLat = len * Math.cos(bearing * 0.01745);
  		var nLng = len * Math.sin(bearing * 0.01745);
  		
  		var linePath = [
  			new google.maps.LatLng(latitude + nLat, longitude + nLng),
  			new google.maps.LatLng(latitude, longitude),
  			new google.maps.LatLng(latitude - nLat, longitude - nLng) ];
  						
  		var lineOptions = {
  			clickable: false,
  			zIndex: 1,
  			strokeColor: colour,
  			strokeOpacity: 0.6,
  			strokeWeight: 3,
  			path: linePath };
  		
  		var line = new google.maps.Polyline(lineOptions);
  		
  		line.setMap(_map); */ //polylines are way too slow...
  		var circleOptions = {
  				center: new google.maps.LatLng(latitude, longitude),
  				clickable: false,
  				fillColor: colour,
  				fillOpacity: 0.4,
  				radius: 3,
  				strokeColor: colour,
  				strokeOpacity: 0.6,
  				strokeWeight: 1,
  				map: _map
  			}
  	
  		var point = new google.maps.Circle(circleOptions);
  		
  		_pointsArray.push(point);
  	}
  	
  	function clearPoints()
  	{
  		if (_pointsArray)
  		{
  			for (i in _pointsArray)
  			{
  				_pointsArray[i].setMap(null);
  			}
  			_pointsArray.length = 0;
  		}
  	}
  	
  	function FollowControl(controlDiv) 
  	{
  		controlDiv.style.padding = '5px';

	  	var controlUI = document.createElement('DIV');
	  	controlUI.style.backgroundColor = 'white';
	  	//controlUI.style.filters.alpha.opacity = 60; //IE
	  	//controlUI.sytle.opacity=0.6; //CSS standard
	  	controlUI.style.borderStyle = 'solid';
	  	controlUI.style.borderWidth = '1px';
  		controlUI.style.cursor = 'pointer';
  		controlUI.style.textAlign = 'center';
  		controlUI.title = 'Click to toggle follow mode';
  		controlDiv.appendChild(controlUI);

  		var controlText = document.createElement('DIV');
  		controlText.style.fontFamily = 'Arial,sans-serif';
  		controlText.style.fontSize = '12px';
  		controlText.style.paddingLeft = '4px';
  		controlText.style.paddingRight = '4px';
  		controlText.innerHTML = 'Toggle Tracking';
  		controlUI.appendChild(controlText);

  		google.maps.event.addDomListener(controlUI, 'click', function() {
    			_followCar = !_followCar;
    			if (_followCar == true)
    			{
    				checkBlipBounds();
    				document.title = "Jam Dodge (Tracking)";
    			}
    			else
    			{
    				document.title = "Jam Dodge";
    			}
  			});
	}

  	
  	function initialize() 
  	{
  		//If we are being run throuhg the android app, use it. Otherwise try use W3C Geolocation.
    	if (window.android)
		{ }
		else if(navigator.geolocation)
		{
	  		var watchId = navigator.geolocation.watchPosition(updatePosViaGeoloc); //set up the callback
		}
		else
		{
			_location = new google.maps.LatLng(-26, 28); //worst case start us at 0,0
		}

		//Create map:
    	var mapOptions = {
      		zoom: 17,
      		center: _location,
      		mapTypeId: google.maps.MapTypeId.ROADMAP,
	  		streetViewControl: false,
	  		mapTypeControl: false
    		}
	
    	_map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
	
		_blipBounds = new google.maps.LatLngBounds(new google.maps.LatLng(-0.2, -0.2), new google.maps.LatLng(-0.1, -0.1)); //will force an update, always
	
		//Create blip:
		var blipOptions = {
			clickable: false,
			flat: true,
			icon: new google.maps.MarkerImage("marker.png", new google.maps.Size(20,20), new google.maps.Point(0,0), new google.maps.Point(10,10)),
			visible: true,
			optimized: true
  			}
  		
  		blip = new google.maps.Marker(blipOptions);
  		
  		blip.setMap(_map);
		blip.setPosition(_location);
		
		google.maps.event.addListener(_map, "bounds_changed", function () {
				if (_followCar == false)
				{
					//we add a bit of a threshold otherwise this could be called lots for some reason
					var newBounds = _map.getBounds();
					var deltaLat = Math.abs(newBounds.getSouthWest().lat() - _blipBounds.getSouthWest().lat());
					var deltaLng = Math.abs(newBounds.getSouthWest().lng() - _blipBounds.getSouthWest().lng());
					_blipBounds = newBounds;
					
					if ((deltaLat >= 0.0001) || (deltaLng >= 0.0001))
					{
						clearPoints();
						sendRequestForPoints();
					}
				}
			} );
			
		//Follow button
		var followButtonDiv = document.createElement('DIV');
		var followButton = new FollowControl(followButtonDiv);
		followButtonDiv.index = 1;
		_map.controls[google.maps.ControlPosition.TOP_RIGHT].push(followButtonDiv);
  	}
